/**
 * Copyright (c) 2011-2020, hubin (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.alinesno.cloud.compoment.generate.generator.config.builder;

import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alinesno.cloud.compoment.generate.generator.StringUtils;
import com.alinesno.cloud.compoment.generate.generator.config.ConstVal;
import com.alinesno.cloud.compoment.generate.generator.config.DataSourceConfig;
import com.alinesno.cloud.compoment.generate.generator.config.GlobalConfig;
import com.alinesno.cloud.compoment.generate.generator.config.PackageConfig;
import com.alinesno.cloud.compoment.generate.generator.config.StrategyConfig;
import com.alinesno.cloud.compoment.generate.generator.config.TemplateConfig;
import com.alinesno.cloud.compoment.generate.generator.config.po.TableField;
import com.alinesno.cloud.compoment.generate.generator.config.po.TableFill;
import com.alinesno.cloud.compoment.generate.generator.config.po.TableInfo;
import com.alinesno.cloud.compoment.generate.generator.config.rules.DbType;
import com.alinesno.cloud.compoment.generate.generator.config.rules.NamingStrategy;
import com.alinesno.cloud.compoment.generate.generator.config.rules.QuerySQL;

/**
 * 配置汇总 传递给文件生成工具
 * @author LuoAnDong
 * @since 2018年2月14日 下午2:51:36
 */
public class ConfigBuilder {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * 模板路径配置信息
	 */
	private final TemplateConfig template;
	/**
	 * 数据库配置
	 */
	private final DataSourceConfig dataSourceConfig;
	/**
	 * SQL连接
	 */
	private Connection connection;
	/**
	 * SQL语句类型
	 */
	private QuerySQL querySQL;
	private String superEntityClass;
	private String superMapperClass;
	
	/**
	 * service超类定义
	 */
	private String superServiceClass;
	private String superServiceImplClass;
	private String superControllerClass;
	private String superRestControllerClass;
	private String superFeiginDtoClass; // FeiginDto
	private String feiginServer ;  //Feigin服务
	private String springBootStart ;  // springboot 启动类模板
	private String bootPrefix ; //springboot前缀
	
	private String superRepositoryClass ; //定义持久层超类
	private String idKeyType ; // 主键生成策略
	
	// 生成 yml 和 pom.xml 文件 
    private String springApplicationName ; 
    private String serverPort ; 
    private String databaseDriverClass ; 
    private String databaseUrl ; 
    private String databaseUsername ; 
    private String databasePassword ; 
    
    private String articleId ; 
    private String groupId ; 
	
	/**
	 * 数据库表信息
	 */
	private List<TableInfo> tableInfoList;

	/**
	 * 跳过不用解析的字段
	 */
	private List<String> skipField ; 
	
	/**
	 * 包配置详情
	 */
	private Map<String, String> packageInfo;
	/**
	 * 路径配置信息
	 */
	private Map<String, String> pathInfo;
	/**
	 * 策略配置
	 */
	private StrategyConfig strategyConfig;

	/**
	 * 全局配置信息
	 */
	private GlobalConfig globalConfig;

	/**
	 * <p>
	 * 在构造器中处理配置
	 * </p>
	 *
	 * @param packageConfig
	 *            包配置
	 * @param dataSourceConfig
	 *            数据源配置
	 * @param strategyConfig
	 *            表配置
	 * @param template
	 *            模板配置
	 * @param globalConfig
	 *            全局配置
	 */
	public ConfigBuilder(PackageConfig packageConfig, DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig,
			TemplateConfig template, GlobalConfig globalConfig) {
		// 全局配置
		if (null == globalConfig) {
			this.globalConfig = new GlobalConfig();
		} else {
			this.globalConfig = globalConfig;
		}
		// 模板配置
		if (null == template) {
			this.template = new TemplateConfig();
		} else {
			this.template = template;
		}
		// 包配置
		if (null == packageConfig) {
			handlerPackage(this.template, this.globalConfig.getOutputDir(), new PackageConfig());
		} else {
			handlerPackage(this.template, this.globalConfig.getOutputDir(), packageConfig);
		}
		this.dataSourceConfig = dataSourceConfig;
		handlerDataSource(dataSourceConfig);
		// 策略配置
		if (null == strategyConfig) {
			this.strategyConfig = new StrategyConfig();
		} else {
			this.strategyConfig = strategyConfig;
		}
		handlerStrategy(this.strategyConfig);
		
		// yml and pom.xml
		this.springApplicationName = packageConfig.getSpringApplicationName() ; 
		this.serverPort = packageConfig.getServerPort() ; 
		this.databaseDriverClass = packageConfig.getDatabaseDriverClass(); 
		this.databaseUrl = packageConfig.getDatabaseUrl(); 
		this.databaseUsername = packageConfig.getDatabaseUsername() ; 
		this.databasePassword = packageConfig.getDatabasePassword() ; 
		
		this.articleId = packageConfig.getArticleId() ; 
		this.groupId = packageConfig.getGroupId() ; 
		
	}

	// ************************ 曝露方法 BEGIN*****************************

	/**
	 * <p>
	 * 所有包配置信息
	 * </p>
	 *
	 * @return 包配置
	 */
	public Map<String, String> getPackageInfo() {
		return packageInfo;
	}

	/**
	 * <p>
	 * 所有路径配置
	 * </p>
	 *
	 * @return 路径配置
	 */
	public Map<String, String> getPathInfo() {
		return pathInfo;
	}

	public Connection getConnection() {
		return connection;
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}

	public QuerySQL getQuerySQL() {
		return querySQL;
	}

	public void setQuerySQL(QuerySQL querySQL) {
		this.querySQL = querySQL;
	}

	public String getSpringApplicationName() {
		return springApplicationName;
	}

	public void setSpringApplicationName(String springApplicationName) {
		this.springApplicationName = springApplicationName;
	}

	public String getServerPort() {
		return serverPort;
	}

	public void setServerPort(String serverPort) {
		this.serverPort = serverPort;
	}

	public String getDatabaseDriverClass() {
		return databaseDriverClass;
	}

	public void setDatabaseDriverClass(String databaseDriverClass) {
		this.databaseDriverClass = databaseDriverClass;
	}

	public String getDatabaseUrl() {
		return databaseUrl;
	}

	public void setDatabaseUrl(String databaseUrl) {
		this.databaseUrl = databaseUrl;
	}

	public String getDatabaseUsername() {
		return databaseUsername;
	}

	public void setDatabaseUsername(String databaseUsername) {
		this.databaseUsername = databaseUsername;
	}

	public String getDatabasePassword() {
		return databasePassword;
	}

	public void setDatabasePassword(String databasePassword) {
		this.databasePassword = databasePassword;
	}

	public String getArticleId() {
		return articleId;
	}

	public void setArticleId(String articleId) {
		this.articleId = articleId;
	}

	public String getGroupId() {
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public Logger getLogger() {
		return logger;
	}

	public DataSourceConfig getDataSourceConfig() {
		return dataSourceConfig;
	}

	public void setSuperEntityClass(String superEntityClass) {
		this.superEntityClass = superEntityClass;
	}

	public void setSuperMapperClass(String superMapperClass) {
		this.superMapperClass = superMapperClass;
	}

	public void setSuperServiceClass(String superServiceClass) {
		this.superServiceClass = superServiceClass;
	}

	public void setSuperServiceImplClass(String superServiceImplClass) {
		this.superServiceImplClass = superServiceImplClass;
	}

	public void setSuperControllerClass(String superControllerClass) {
		this.superControllerClass = superControllerClass;
	}

	public void setTableInfoList(List<TableInfo> tableInfoList) {
		this.tableInfoList = tableInfoList;
	}

	public void setPackageInfo(Map<String, String> packageInfo) {
		this.packageInfo = packageInfo;
	}

	public void setPathInfo(Map<String, String> pathInfo) {
		this.pathInfo = pathInfo;
	}

	public String getSuperEntityClass() {
		return superEntityClass;
	}

	public String getSuperMapperClass() {
		return superMapperClass;
	}

	/**
	 * <p>
	 * 获取超类定义
	 * </p>
	 *
	 * @return 完整超类名称
	 */
	public String getSuperServiceClass() {
		return superServiceClass;
	}

	public String getSuperServiceImplClass() {
		return superServiceImplClass;
	}

	public String getSuperControllerClass() {
		return superControllerClass;
	}

	/**
	 * <p>
	 * 表信息
	 * </p>
	 *
	 * @return 所有表信息
	 */
	public List<TableInfo> getTableInfoList() {
		return tableInfoList;
	}

	/**
	 * <p>
	 * 模板路径配置信息
	 * </p>
	 *
	 * @return 所以模板路径配置信息
	 */
	public TemplateConfig getTemplate() {
		return template == null ? new TemplateConfig() : template;
	}

	// ****************************** 曝露方法 END**********************************

	/**
	 * <p>
	 * 处理包配置
	 * </p>
	 *
	 * @param template
	 *            TemplateConfig
	 * @param outputDir
	 * @param config
	 *            PackageConfig
	 */
	private void handlerPackage(TemplateConfig template, String outputDir, PackageConfig config) {
		packageInfo = new HashMap<>();
		packageInfo.put(ConstVal.MODULENAME, config.getModuleName());
		packageInfo.put(ConstVal.ENTITY, joinPackage(config.getParent(), config.getEntity()));
		packageInfo.put(ConstVal.SERIVCE, joinPackage(config.getParent(), config.getService()));
		packageInfo.put(ConstVal.SERVICEIMPL, joinPackage(config.getParent(), config.getServiceImpl()));
		packageInfo.put(ConstVal.SERVICE_AUTO_IMPL, joinPackage(config.getParent(), config.getServiceImpl()));
		
		String controllerPackage = joinPackage(config.getParent(), config.getController());
		packageInfo.put(ConstVal.CONTROLLER, controllerPackage) ; 
		
		// 添加repository路径 
		packageInfo.put(ConstVal.REPOSITORY, joinPackage(config.getParent(), config.getRepository()));
		
		// 添加rest路径 
		packageInfo.put(ConstVal.REST_CONTROLLER, joinPackage(config.getParent(), config.getRestController()));
		
		// 添加boot路径
		packageInfo.put(ConstVal.BOOT, config.getParent());
		
		// 添加feigin路径 
		packageInfo.put(ConstVal.FEIGIN , joinPackage(config.getParent(), config.getFeigin()));
		packageInfo.put(ConstVal.FEIGIN_DTO , joinPackage(config.getParent(), config.getFeiginDto()));
	
		// jsp页面路径 
		packageInfo.put(ConstVal.PAGE, joinPackage(config.getParent(), config.getPage()));

		// 生成路径信息
		pathInfo = new HashMap<>();
		if (StringUtils.isNotEmpty(template.getEntity())) {
			pathInfo.put(ConstVal.ENTITY_PATH, joinPath(outputDir, packageInfo.get(ConstVal.ENTITY)));
		}
		if (StringUtils.isNotEmpty(template.getService())) {
			pathInfo.put(ConstVal.SERIVCE_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERIVCE)));
		}
		if (StringUtils.isNotEmpty(template.getServiceImpl())) {
			pathInfo.put(ConstVal.SERVICEIMPL_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERVICEIMPL)));
		}
		if (StringUtils.isNotEmpty(template.getController())) {
			pathInfo.put(ConstVal.CONTROLLER_PATH, joinPath(outputDir, packageInfo.get(ConstVal.CONTROLLER)));
		}
		
		// 生成spring data jpa页面路径 
		if (StringUtils.isNotEmpty(template.getRepository())) {
			pathInfo.put(ConstVal.REPOSITORY_PATH, joinPath(outputDir, packageInfo.get(ConstVal.REPOSITORY)));
		}
		
		// 生成rest controller页面路径 
		if (StringUtils.isNotEmpty(template.getRestController())) {
			pathInfo.put(ConstVal.REST_CONTROLLER_PATH , joinPath(outputDir, packageInfo.get(ConstVal.REST_CONTROLLER)));
		}
		
		// 生成 feigin 页面路径 
		if (StringUtils.isNotEmpty(template.getFeigin())) {
			pathInfo.put(ConstVal.FEIGIN_API_PATH , joinPath(outputDir, packageInfo.get(ConstVal.FEIGIN)));
		}
		
		// 生成 feigin dto 页面路径
		if (StringUtils.isNotEmpty(template.getFeiginDto())) {
			pathInfo.put(ConstVal.FEIGIN_DTO_PATH , joinPath(outputDir, packageInfo.get(ConstVal.FEIGIN_DTO)));
		}
		
		// 生成 boot 路径
		if (StringUtils.isNotEmpty(template.getBoot())) {
			pathInfo.put(ConstVal.BOOT , outputDir);
		}
		
		//生成jsp页面路径 
		if (StringUtils.isNotEmpty(template.getPageList())) {
			logger.debug("===> list:{} , path:{}, info:{}" , ConstVal.PAGE_LIST_PATH , joinJSPPath(outputDir, packageInfo.get(ConstVal.PAGE)) , packageInfo.get(ConstVal.PAGE));	
			pathInfo.put(ConstVal.PAGE_LIST_PATH, joinJSPPath(outputDir, packageInfo.get(ConstVal.PAGE)));
		}
		if (StringUtils.isNotEmpty(template.getPageAdd())) {
			pathInfo.put(ConstVal.PAGE_ADD_PATH, joinJSPPath(outputDir, packageInfo.get(ConstVal.PAGE)));
		}
		if (StringUtils.isNotEmpty(template.getPageModify())) {
			pathInfo.put(ConstVal.PAGE_MODIFY_PATH, joinJSPPath(outputDir, packageInfo.get(ConstVal.PAGE)));
		}
		if (StringUtils.isNotEmpty(template.getPageDetail())) {
			pathInfo.put(ConstVal.PAGE_DETAIL_PATH, joinJSPPath(outputDir, packageInfo.get(ConstVal.PAGE)));
		}
	}

	/**
	 * <p>
	 * 处理数据源配置
	 * </p>
	 *
	 * @param config
	 *            DataSourceConfig
	 */
	private void handlerDataSource(DataSourceConfig config) {
		connection = config.getConn();
		querySQL = getQuerySQL(config.getDbType());
	}

	/**
	 * <p>
	 * 处理数据库表 加载数据库表、列、注释相关数据集
	 * </p>
	 *
	 * @param config
	 *            StrategyConfig
	 */
	private void handlerStrategy(StrategyConfig config) {
		processTypes(config);
		tableInfoList = getTablesInfo(config);
	}

	/**
	 * <p>
	 * 处理superClassName,IdClassType,IdStrategy配置
	 * </p>
	 *
	 * @param config
	 *            策略配置
	 */
	private void processTypes(StrategyConfig config) {
		if (StringUtils.isEmpty(config.getSuperServiceClass())) {
			superServiceClass = ConstVal.SUPERD_SERVICE_CLASS;
		} else {
			superServiceClass = config.getSuperServiceClass();
		}
		
		if (StringUtils.isEmpty(config.getSuperServiceImplClass())) {
			superServiceImplClass = ConstVal.SUPERD_SERVICEIMPL_CLASS;
		} else {
			superServiceImplClass = config.getSuperServiceImplClass();
		}
		
		
		if (StringUtils.isEmpty(config.getSuperMapperClass())) {
			superMapperClass = ConstVal.SUPERD_MAPPER_CLASS;
		} else {
			superMapperClass = config.getSuperMapperClass();
		}
		
		if (StringUtils.isEmpty(config.getSuperRepositoryClass())) {
			superRepositoryClass = ConstVal.SUPER_REPOSITORY_CLASS;
		} else {
			superRepositoryClass = config.getSuperRepositoryClass() ;
		}
		
		idKeyType = config.getIdKeyType() ; 
		superEntityClass = config.getSuperEntityClass();
		superControllerClass = config.getSuperControllerClass();
		superRestControllerClass = config.getSuperRestControllerClass() ; 
		superFeiginDtoClass = config.getSuperFeiginDtoClass() ; 
		feiginServer = config.getFeiginServer() ; 
		bootPrefix = config.getBootPrefix() ; 
	}

	/**
	 * <p>
	 * 处理表对应的类名称
	 * </P>
	 *
	 * @param tableList
	 *            表名称
	 * @param strategy
	 *            命名策略
	 * @param tablePrefix
	 * @return 补充完整信息后的表
	 */
	private List<TableInfo> processTable(List<TableInfo> tableList, NamingStrategy strategy, String[] tablePrefix) {
		
		for (TableInfo tableInfo : tableList) {
			
			tableInfo.setEntityName(strategyConfig,NamingStrategy.capitalFirst(processName(tableInfo.getName(), strategy, tablePrefix)));
			
			if (StringUtils.isNotEmpty(globalConfig.getMapperName())) {
				tableInfo.setMapperName(String.format(globalConfig.getMapperName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setMapperName(tableInfo.getEntityName() + ConstVal.MAPPER);
			}
			if (StringUtils.isNotEmpty(globalConfig.getXmlName())) {
				tableInfo.setXmlName(String.format(globalConfig.getXmlName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setXmlName(tableInfo.getEntityName() + ConstVal.MAPPER);
			}
			if (StringUtils.isNotEmpty(globalConfig.getServiceName())) {
				tableInfo.setServiceName(String.format(globalConfig.getServiceName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setServiceName("I" + tableInfo.getEntityName() + ConstVal.SERIVCE);
			}
			if (StringUtils.isNotEmpty(globalConfig.getServiceImplName())) {
				tableInfo.setServiceImplName(String.format(globalConfig.getServiceImplName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setServiceImplName(tableInfo.getEntityName() + ConstVal.SERVICEIMPL);
			}
			if (StringUtils.isNotEmpty(globalConfig.getControllerName())) {
				tableInfo.setControllerName(String.format(globalConfig.getControllerName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setControllerName(tableInfo.getEntityName() + ConstVal.CONTROLLER);
			}
		
			// 设置repository名称
			if (StringUtils.isNotEmpty(globalConfig.getRepositoryName())) {
				tableInfo.setRepositoryName(String.format(globalConfig.getControllerName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setRepositoryName(tableInfo.getEntityName() + ConstVal.REPOSITORY);
			}
			
			// 设置rest controller 名称
			if (StringUtils.isNotEmpty(globalConfig.getRestControllerName())) {
				tableInfo.setRestControllerName(String.format(globalConfig.getRestControllerName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setRestControllerName(tableInfo.getEntityName() + ConstVal.REST_CONTROLLER);
			}
			
			// 设置feigin 名称
			if (StringUtils.isNotEmpty(globalConfig.getFeiginName())) {
				tableInfo.setFeiginName(String.format(globalConfig.getFeiginName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setFeiginName(tableInfo.getEntityName() + ConstVal.FEIGIN);
			}
			
			// 设置feigin dto 名称
			if (StringUtils.isNotEmpty(globalConfig.getFeiginDtoName())) {
				tableInfo.setFeiginDtoName(String.format(globalConfig.getFeiginDtoName(), tableInfo.getEntityName()));
			} else {
				tableInfo.setFeiginDtoName(tableInfo.getEntityName() + ConstVal.FEIGIN_DTO);
			}
			
			//设置JSP名称
        	String entityPath = tableInfo.getEntityPath().replaceAll(ConstVal.ENTITY, "") ;
        	String pagePath = "templates/"+globalConfig.getModuleName()+"/"+entityPath +"/"; 
        	
        	
			tableInfo.setPagelistPageName(pagePath+"list"+ConstVal.HTML_SUFFIX);
			tableInfo.setPageAddPageName(pagePath+"add"+ConstVal.HTML_SUFFIX);
			tableInfo.setPageModifyPageName(pagePath+"modify"+ConstVal.HTML_SUFFIX);
			tableInfo.setPageDetailPageName(pagePath+"detail"+ConstVal.HTML_SUFFIX);
			
			//设置SOA映射组件名称
			tableInfo.setSOAEntityName(tableInfo.getEntityName()+ConstVal.ENTITY);
		}
		return tableList;
	}

	/**
	 * <p>
	 * 获取所有的数据库表信息
	 * </p>
	 */
	private List<TableInfo> getTablesInfo(StrategyConfig config) {
		boolean isInclude = (null != config.getInclude() && config.getInclude().length > 0);
		boolean isExclude = (null != config.getExclude() && config.getExclude().length > 0);
		if (isInclude && isExclude) {
			throw new RuntimeException("<strategy> 标签中 <include> 与 <exclude> 只能配置一项！");
		}
		// 所有的表信息
		List<TableInfo> tableList = new ArrayList<>();

		// 需要反向生成或排除的表信息
		List<TableInfo> includeTableList = new ArrayList<>();
		List<TableInfo> excludeTableList = new ArrayList<>();

		// 不存在的表名
		Set<String> notExistTables = new HashSet<>();

		NamingStrategy strategy = config.getNaming();
		PreparedStatement preparedStatement = null;
		try {
			String tableCommentsSql = querySQL.getTableCommentsSql();
			if (QuerySQL.POSTGRE_SQL == querySQL) {
				tableCommentsSql = String.format(tableCommentsSql, dataSourceConfig.getSchemaname());
			}
			
			TableInfo tableInfo;
			preparedStatement = connection.prepareStatement(tableCommentsSql);
			ResultSet results = preparedStatement.executeQuery();
		
			
			while (results.next()) {
				String tableName = results.getString(querySQL.getTableName());
				if (StringUtils.isNotEmpty(tableName)) {
					
					String[] tablePrefix = config.getTablePrefix() ; 
					boolean isContain = isHasPrefix(tablePrefix , tableName); 
					if(isContain) {
						String tableComment = results.getString(querySQL.getTableComment());
						tableInfo = new TableInfo();
						tableInfo.setName(tableName);
						tableInfo.setComment(tableComment);
						if (isInclude) {
							for (String includeTab : config.getInclude()) {
								if (includeTab.equalsIgnoreCase(tableName)) {
									includeTableList.add(tableInfo);
								} else {
									notExistTables.add(includeTab);
								}
							}
						} else if (isExclude) {
							for (String excludeTab : config.getExclude()) {
								if (excludeTab.equalsIgnoreCase(tableName)) {
									excludeTableList.add(tableInfo);
								} else {
									notExistTables.add(excludeTab);
								}
							}
						}
						tableList.add(this.convertTableFields(tableInfo, strategy));
					}
				} else {
					System.err.println("当前数据库为空！！！");
				}
			}
			
			// 将已经存在的表移除，获取配置中数据库不存在的表
			for (TableInfo tabInfo : tableList) {
				notExistTables.remove(tabInfo.getName());
			}

			if (notExistTables.size() > 0) {
				System.err.println("表 " + notExistTables + " 在数据库中不存在！！！");
			}

			// 需要反向生成的表信息
			if (isExclude) {
				tableList.removeAll(excludeTableList);
				includeTableList = tableList;
			}
			if (!isInclude && !isExclude) {
				includeTableList = tableList;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// 释放资源
			try {
				if (preparedStatement != null) {
					preparedStatement.close();
				}
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return processTable(includeTableList, strategy, config.getTablePrefix());
	}

	/**
	 * 判断是否包含前缀
	 * @param tablePrefix
	 * @param tableName
	 * @return
	 */
	private boolean isHasPrefix(String[] tablePrefix, String tableName) {
		boolean b = false ; 
		if(tablePrefix == null || tablePrefix.length == 0) {
			return true ; 
		}
		for(String p : tablePrefix) {
			if(tableName.startsWith(p)) {
				b = true ; 
				break ; 
			}
		}
		return b ;
	}

	/**
	 * <p>
	 * 判断主键是否为identity，目前仅对mysql进行检查
	 * </p>
	 *
	 * @param results
	 *            ResultSet
	 * @return 主键是否为identity
	 * @throws SQLException
	 */
	private boolean isKeyIdentity(ResultSet results) throws SQLException {
		if (QuerySQL.MYSQL == this.querySQL) {
			String extra = results.getString("Extra");
			if ("auto_increment".equals(extra)) {
				return true;
			}
		} else if (QuerySQL.SQL_SERVER == this.querySQL) {
			int isIdentity = results.getInt("isIdentity");
			return 1 == isIdentity;
		}
		return false;
	}

	/**
	 * <p>
	 * 将字段信息与表信息关联
	 * </p>
	 *
	 * @param tableInfo
	 *            表信息
	 * @param strategy
	 *            命名策略
	 * @return
	 */
	private TableInfo convertTableFields(TableInfo tableInfo, NamingStrategy strategy) {

		logger.debug("table info = {} , name = {}", tableInfo, tableInfo.getName());

		boolean haveId = false;
		List<TableField> fieldList = new ArrayList<>();
		List<TableField> commonFieldList = new ArrayList<>();

		try {
			String tableFieldsSql = querySQL.getTableFieldsSql();
			if (QuerySQL.POSTGRE_SQL == querySQL) {
				tableFieldsSql = String.format(tableFieldsSql, dataSourceConfig.getSchemaname(), tableInfo.getName());
			} else {
				tableFieldsSql = String.format(tableFieldsSql, tableInfo.getName());
			}

			logger.debug("table fields sql= {}", tableFieldsSql);

			PreparedStatement preparedStatement = connection.prepareStatement(tableFieldsSql);
			ResultSet results = preparedStatement.executeQuery();

			logger.debug("results = {}", results);

			while (results.next()) {
				TableField field = new TableField();
				
				String key = results.getString(querySQL.getFieldKey());
				// 避免多重主键设置，目前只取第一个找到ID，并放到list中的索引为0的位置
				boolean isId = StringUtils.isNotEmpty(key) && key.toUpperCase().equals("PRI");
				// 处理ID
				if (isId && !haveId) {
					field.setKeyFlag(true);
					if (isKeyIdentity(results)) {
						field.setKeyIdentityFlag(true);
					}
					haveId = true;
				} else {
					field.setKeyFlag(false);
				}
				// 处理其它信息
				field.setName(results.getString(querySQL.getFieldName()));
				field.setType(results.getString(querySQL.getFieldType()));
				field.setPropertyName(strategyConfig, processName(field.getName(), strategy));
				field.setColumnType(dataSourceConfig.getTypeConvert().processTypeConvert(field.getType()));
				field.setComment(results.getString(querySQL.getFieldComment()));
				if (strategyConfig.includeSuperEntityColumns(field.getName())) {
					// 跳过公共字段
					commonFieldList.add(field);
					continue;
				}
				// 填充逻辑判断
				List<TableFill> tableFillList = this.getStrategyConfig().getTableFillList();
				if (null != tableFillList) {
					for (TableFill tableFill : tableFillList) {
						if (tableFill.getFieldName().equals(field.getName())) {
							field.setFill(tableFill.getFieldFill().name());
							break;
						}
					}
				}
			
				fieldList.add(field);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		tableInfo.setFields(fieldList);
		tableInfo.setCommonFields(commonFieldList);
		return tableInfo;
	}

	/**
	 * <p>
	 * 连接路径字符串
	 * </p>
	 *
	 * @param parentDir
	 *            路径常量字符串
	 * @param packageName
	 *            包名
	 * @return 连接后的路径
	 */
	private String joinPath(String parentDir, String packageName) {
		if (StringUtils.isEmpty(parentDir)) {
			parentDir = System.getProperty(ConstVal.JAVA_TMPDIR);
		}
		if (!StringUtils.endsWith(parentDir, File.separator)) {
			parentDir += File.separator;
		}
		packageName = packageName.replaceAll("\\.", "\\" + File.separator);
		
		
		//增加src/main/java
		
		logger.debug("java name = {}" , packageName);
		return parentDir + ConstVal.COMPILER_PATH_JAVA + packageName;
	}
	
	/**
	 * 生成页面路径 
	 * @param outputDir
	 * @param string
	 * @return
	 */
	private String joinJSPPath(String parentDir, String packageName) {
		if (StringUtils.isEmpty(parentDir)) {
			parentDir = System.getProperty(ConstVal.JAVA_TMPDIR);
		}
		if (!StringUtils.endsWith(parentDir, File.separator)) {
			parentDir += File.separator;
		}
		packageName = packageName.replaceAll("\\.", "\\" + File.separator) ;
		logger.debug("resource name = {}" , packageName.substring(0 , packageName.lastIndexOf(File.separator)));
		
		//增加src/main/resource
		
		return parentDir +  ConstVal.COMPILER_PATH_RESOUCE ;//+ packageName.substring(0 , packageName.lastIndexOf(File.separator)) ;
	}


	/**
	 * <p>
	 * 连接父子包名
	 * </p>
	 *
	 * @param parent
	 *            父包名
	 * @param subPackage
	 *            子包名
	 * @return 连接后的包名
	 */
	private String joinPackage(String parent, String subPackage) {
		if (StringUtils.isEmpty(parent)) {
			return subPackage;
		}
	
		logger.debug("package parent = {} , subPackage:{}" , parent  , subPackage);
		
		String p = (parent + "." + subPackage).replaceAll("/", ".") ;
		
		return p ; 
	}

	/**
	 * <p>
	 * 处理字段名称
	 * </p>
	 *
	 * @return 根据策略返回处理后的名称
	 */
	private String processName(String name, NamingStrategy strategy) {
		return processName(name, strategy, null);
	}

	/**
	 * <p>
	 * 处理字段名称
	 * </p>
	 *
	 * @param name
	 * @param strategy
	 * @param tablePrefix
	 * @return 根据策略返回处理后的名称
	 */
	private String processName(String name, NamingStrategy strategy, String[] tablePrefix) {
		boolean removePrefix = false;
		if (tablePrefix != null && tablePrefix.length >= 1) {
			removePrefix = true;
		}
		String propertyName;
		if (removePrefix) {
			if (strategy == NamingStrategy.underline_to_camel) {
				// 删除前缀、下划线转驼峰
				propertyName = NamingStrategy.removePrefixAndCamel(name, tablePrefix);
			} else {
				// 删除前缀
				propertyName = NamingStrategy.removePrefix(name, tablePrefix);
			}
		} else if (strategy == NamingStrategy.underline_to_camel) {
			// 下划线转驼峰
			propertyName = NamingStrategy.underlineToCamel(name);
		} else {
			// 不处理
			propertyName = name;
		}
		return propertyName;
	}

	/**
	 * 获取当前的SQL类型
	 *
	 * @return DB类型
	 */
	private QuerySQL getQuerySQL(DbType dbType) {
		for (QuerySQL qs : QuerySQL.values()) {
			if (qs.getDbType().equals(dbType.getValue())) {
				return qs;
			}
		}
		return QuerySQL.MYSQL;
	}

	public StrategyConfig getStrategyConfig() {
		return strategyConfig;
	}

	public ConfigBuilder setStrategyConfig(StrategyConfig strategyConfig) {
		this.strategyConfig = strategyConfig;
		return this;
	}

	public GlobalConfig getGlobalConfig() {
		return globalConfig;
	}

	public ConfigBuilder setGlobalConfig(GlobalConfig globalConfig) {
		this.globalConfig = globalConfig;
		return this;
	}

	public String getSuperRepositoryClass() {
		return superRepositoryClass;
	}

	public void setSuperRepositoryClass(String superRepositoryClass) {
		this.superRepositoryClass = superRepositoryClass;
	}

	public String getIdKeyType() {
		return idKeyType;
	}

	public void setIdKeyType(String idKeyType) {
		this.idKeyType = idKeyType;
	}

	public List<String> getSkipField() {
		return skipField;
	}

	public void setSkipField(List<String> skipField) {
		this.skipField = skipField;
	}

	public String getSuperRestControllerClass() {
		return superRestControllerClass;
	}

	public void setSuperRestControllerClass(String superRestControllerClass) {
		this.superRestControllerClass = superRestControllerClass;
	}

	public String getSuperFeiginDtoClass() {
		return superFeiginDtoClass;
	}

	public void setSuperFeiginDtoClass(String superFeiginDtoClass) {
		this.superFeiginDtoClass = superFeiginDtoClass;
	}

	public String getFeiginServer() {
		return feiginServer;
	}

	public void setFeiginServer(String feiginServer) {
		this.feiginServer = feiginServer;
	}

	public String getSpringBootStart() {
		return springBootStart;
	}

	public void setSpringBootStart(String springBootStart) {
		this.springBootStart = springBootStart;
	}

	public String getBootPrefix() {
		return bootPrefix;
	}

	public void setBootPrefix(String bootPrefix) {
		this.bootPrefix = bootPrefix;
	}

}
